const fs = require('fs');
const path = require('path');
const babel = require('@babel/core');
const t = require('@babel/types');
const g = require('@babel/generator');

const vueFileList = [];
const jsFileList = [];
const rootPath = process.cwd();
const includeFolderPaths = ['lib', 'src'];
const includeFilePaths = ['a.js'];
const fileMap = new Map();

console.warn('rootPath', rootPath);
// 1.遍历所有js文件，替换关联代码，保存
// 如果是导出，查看关联文件并替换
getFiles();
// 2.替换vue文件
console.warn('vueFileList', vueFileList);
console.warn('jsFileList', jsFileList);
/*
    {
        filePath, 文件路径
        fnName, 函数名称
        relate, 被引用数量
        refer,应用列表
    }
*/
/* 文件路径 = {
    函数名称: {
        refer: [], 引用了其他的
        needDel: false,
        relate: 被引用
    }
}*/
// 生成需要导出的数据结构
// 只有一级引用的删除函数
// 文件未包含函数，删除
rep();

function rep() {
    let i = 0;
    while (i < jsFileList.length) {
        const p = jsFileList[i];
        const f = fs.readFileSync(p, 'utf8');
        if (f.includes('methods') || f.includes('mounted') || f.includes('mixins') || f.includes('created')) {
            vueFileList.push(f);
            repCon(f, p);
            ++i;
        } else {
            fileMap.set(f, []);
            repCon(f, p);
            createRef();
            ++i;
        }
    }
}

function repCon(c, f) {
    console.warn(f);
    const vars = fileMap.get(f);// 所有导出的函数列表
    const impts = {};
    const { ast , code } = babel.transformSync(c, {
        plugins: [{
            visitor: {
                ImportDeclaration(p) {
                    // 收集依赖
                    console.warn('ImportDeclaration');
                    // . @ ~ /
                    const url = p.get("source").node.value;
                    console.warn(url);
                    if (url.startsWith(".") || url.startsWith("/") || url.startsWith("@") || url.startsWith("~")) {
                        p.get("specifiers").forEach((item) => {
                            // item.get();
                            console.warn(t.isImportNamespaceSpecifier(item));
                            if (t.isImportNamespaceSpecifier(item)) {
                                const name = item.get('local').node.name;
                                impts[name] = {
                                    filePath: getAbsolutePath(f, url),
                                    type: 'ImportNamespaceSpecifier',
                                    name,
                                };
                                console.warn('ImportNamespaceSpecifier', name);
                            
                            } else if (t.isImportDefaultSpecifier(item)) {
                                const name = item.get('local').node.name;
                                impts[name] = {
                                    filePath: getAbsolutePath(f, url),
                                    type: 'ImportDefaultSpecifier',
                                    name,
                                };
                                console.warn('isImportDefaultSpecifier', name);
                            
                            } else if (t.isImportSpecifier(item)) {
                                const name = item.get('local').node.name;
                                impts[name] = {
                                    filePath: getAbsolutePath(f, url),
                                    type: 'ImportSpecifier',
                                    name,
                                };
                                console.warn('isImportSpecifier', name);
                            }
                        });
                    }
                },
                ExportDefaultDeclaration(p) {
                    console.warn('ExportDefaultDeclaration');
                },
                ExportNamedDeclaration(p) {
                    console.warn('ExportNamedDeclaration');
                    if (p.get("declaration.type") === 'FunctionDeclaration') {
                        const fnname = p.get("declaration.id.name");
                        
                        const obj = {
                            type: 'fn',
                            filePath: f,
                            fnName: fnname,
                            relate: 0, // 被引用的数量
                            refer: [], // 引用
                        };
                        // 获取所有引用
                        vars[fnname] = obj;
                    } else if (p.get("declaration.type") === 'VariableDeclaration') {
                        const fnname = p.get("declaration.declarations.0.id.name");
                        const obj = {
                            type: 'var',
                            filePath: f,
                            fnName: fnname,
                            relate: 0, // 被引用的数量
                            refer: [], // 引用
                        };
                        // 获取所有引用
                        
                        vars[fnname] = obj;
                    }
                },
                CallExpression(p) {
                    const c = p.get('callee');
                    if (t.isIdentifier(c)) {
                        console.warn('isIdentifier', c.node.name);
                        c.findParent((p) => p.isObjectMethod());
                        // 查找导出的父级节点并建立对应关系
                    } else if (t.isMemberExpression(c)) {
                        console.warn('isMemberExpression-object', c.get('object').node.name);
                        console.warn('isMemberExpression-property', c.get('property').node.name);
                    }
                },
            }
        }, ['./plugins/po.js', {
            obj: 'Http',
            pro: 'callService'
        }]],
        ast: true,
    });
    // console.warn(ast, code);
    // console.warn(g, g.default);
    
    // const output = g.default(ast, {}, code);
    console.warn(impts);
}

function getAbsolutePath(fe, p) {
    if (p.startsWith('~/')) {
        return p.replace('~', rootPath);
    } else if (p.startsWith('~@/')) {
        return p.replace('~@', rootPath);
    } else if (p.startsWith('~')) {
        return p.replace('~', `${rootPath}/`);
    } else if (p.startsWith('@')) {
        return p.replace('@', `${rootPath}/`);
    } else {
        const arr = p.split('/');
        let np = '';
        let fp = path.resolve(fe, '..');
        const parr = [];
        while (arr.length > 0) {
            const lt = arr.pop();
            if (lt === '..') {
                parr.unshift(lt);
                fp = path.resolve(fp, '..');
            } else if (lt === '.') {
                parr.unshift(lt);
            } else if (np) {
                np = `${lt}/${np}`;
            } else {
                np = lt;
            }
        }
        return `${fp}/${np}`;
    }
}

function getAbsolutePathFromBase() {

}

function createRef(ast) {

}

function getFiles() {
    let i = 0;
    const dirs = getDirs(rootPath, includeFolderPaths);
    while (i < dirs.length) {
        const f = dirs[i++];
        const st = fs.lstatSync(f);
        if (st.isDirectory(f)) {
            dirs.push(...getDirs(f));
        } else {
            const ext = includeFilePaths.length > 0 && includeFilePaths.some((item) => f.endsWith(item));
            if (ext === false) {
                continue;
            }
            const extname = path.extname(f);
            if (extname === '.vue') {
                vueFileList.push(f);
            } else if (extname === '.js') {
                jsFileList.push(f);
            } else if (extname === '.mjs') {
                jsFileList.push(f);
            }
        }
    }
}

function getDirs(rp, include = []) {
    return fs
        .readdirSync(rp)
        .filter((f) => {
            if (include.length <= 0) {
                return true;
            }
            return include.includes(f);
        })
        .map((f) => {
            return path.resolve(rp, f);
        });
}
